package org.brisling.base.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.brisling.base.domain.ListDomain;
import org.brisling.base.domain.RetDomain;
import org.brisling.base.domain.inf.BaseDomainInf;
import org.brisling.base.repository.BaseRepository;
import org.brisling.common.ConstSysParam;
import org.brisling.common.util.JsonUtil;
import org.brisling.common.util.LongUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
/**
 * 
 * 默认服务基类，调用spring默认 <code>EntityManager</code>数据访问的业务类可继承该方法
 * @author : jackson wang
 * @Date   : 2015年6月8日 下午9:47:33
 * @version: 1.0
 * @param <T> 泛型需定义的业务类实体
 */
public class BaseService<T extends BaseDomainInf> extends AbstractBaseService{
		
	protected CriteriaBuilder criteriaBuilder =null;
	
	protected Class<T> clazz;
	
	CriteriaQuery<T> criteriaQuery = null;
	
	Root<T> root = null;	
	
	protected BaseRepository<T,Long> baseRepo = null;	
	
	@Autowired
	protected void setService(BaseRepository<T,Long> baseRepo){
		this.baseRepo = baseRepo;		
	}	
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getPagedList(java.lang.String, java.lang.String)
	 */
	public ListDomain<T> getPagedList(String page,String pageSize){			
		
		return this.getAllListDomain(page, pageSize, defaultSort);
		
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getPagedList(java.lang.String, java.lang.String)
	 */
	public ListDomain<T> getPagedList(Integer page,Integer pageSize){			
		
		return this.getAllListDomain(page, pageSize, defaultSort);
		
	}
	
	
	
	/**
	 * 根据实体名称集合获取实体集合
	 * @param names
	 * @return
	 */
	protected List<T> getListByNames(List<String> names){
		return this.baseRepo.findByName(names);
	}
	
	
	/**
	 * 根据实体id集合获取实体集合
	 * @param ids
	 * @return
	 */
	protected List<T> getListByStrIds(List<String> ids){
		
		return this.baseRepo.findById(LongUtil.getLongList(ids));
	}
	
	/**
	 * 根据实体id集合获取实体集合
	 * @param ids
	 * @return
	 */
	protected List<T> getListByLongIds(List<Long> ids){
		return this.baseRepo.findById(ids);
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getPagedList(java.lang.String, java.lang.String, java.lang.String)
	 */
	public ListDomain<T> getPagedList(String page,String pageSize,String sort){		
		
		Sort _sort = sort==null? defaultSort :new Sort(new String[]{sort}) ;
		
		return this.getAllListDomain(page, pageSize, _sort);
		
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getPagedList(java.lang.String, java.lang.String, org.springframework.data.domain.Sort)
	 */
	public ListDomain<T> getPagedList(String page,String pageSize,Sort sort){
		
		
		Integer _page = LongUtil.getIntValue(page, 1);
		Integer _pageSize = LongUtil.getIntValue(pageSize, 10);
		
		
		ListDomain<T> listDomain = new ListDomain<T>();
		
		Sort _sort = sort==null?defaultSort:sort;
		
		
		PageRequest _pageRequest = 
				getPageRequest(_page,_pageSize,_sort);
		
		Page<T> _usrList = baseRepo.findAll(_pageRequest);		
		
		listDomain.setTotal(_usrList.getTotalElements());
		listDomain.setRows(_usrList.getContent());
		
		return listDomain;
		
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getAllListDomain(java.lang.String, java.lang.String, org.springframework.data.domain.Sort)
	 */
	public ListDomain<T> getAllListDomain(String page,String pageSize,Sort sort){
		
		
				
		Integer[] pageParam = this.getPageParam(page, pageSize);
		return this.getAllListDomain(pageParam[0], pageParam[1], sort);
			
	}
	
public ListDomain<T> getAllListDomain(Integer _page,Integer _pageSize,Sort sort){
		
		
			
		
		Sort _sort = sort==null?defaultSort:sort;
		ListDomain<T> listDomain = new ListDomain<T>();
		Page<T> pageList = null;
		if((_page!=null) && (_pageSize!=null)){
			pageList= baseRepo.findAll(this.getPageRequest(_page, _pageSize, _sort));
			listDomain.setTotal(pageList.getTotalElements());
			listDomain.setRows(pageList.getContent());
		}else{
			List<T> List = baseRepo.findAll(_sort );
			listDomain.setTotal((long) List.size());
			listDomain.setRows(List);
		}			
		
		return listDomain;
			
	}
	
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getAllList(org.springframework.data.domain.Sort)
	 */
	public List<T> getAllList(Sort sort){
		Sort _sort = sort==null?defaultSort:sort;
		List<T> list = baseRepo.findAll(_sort);			
		return list;			
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getAll(org.springframework.data.domain.Sort)
	 */
	public List<T> getAll(Sort sort){
		Sort _sort = sort==null?defaultSort:sort;
		List<T> list = baseRepo.findAll(_sort);	
		
		return list;
			
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getAll(java.lang.String, java.lang.String, org.springframework.data.domain.Sort)
	 */
	public List<T> getAll(String page,String pageSize,Sort sort){
		
		
		Integer _page = LongUtil.getIntValue(page, 1);
		Integer _pageSize = LongUtil.getIntValue(pageSize, 10);	
		
		
		Sort _sort = sort==null?defaultSort:sort;
		if(_page!=null && _pageSize!=null){
			Page<T> pageList =  baseRepo.findAll(this.getPageRequest(_page, _pageSize, _sort));
			return pageList.getContent();
		}
		
		List<T> list = baseRepo.findAll(_sort );	
		return list;
			
	}
	
	/**
	 * 保存实体，bizno为空，自动生成bizno
	 * @param t
	 * @return
	 */
	public T save(T t){
		
		//自动生成业务编号
		
		if(t!=null){
			
			
			String _bizno = t.getBizno();
			if(_bizno==null || _bizno.trim().length()<=0){
				t.setBizno(this.generateBizno());
			}
		}
		return  saveNoBizno(t);
	}
	
	/**
	 * 保存实体，根据是否为空自动填充创建时间，自动更新modidate
	 * @param t
	 * @return
	 */
	public T saveNoBizno(T t){
		if(t!=null){
			t.setModiDate(new Date());
			if(t.getCreateTime()==null){
				t.setCreateTime(new Date());
			}
		}
		return   baseRepo.save(t);
	}
	
	/**
	 * 批量保存
	 * @param list
	 * @return
	 */
	public RetDomain saveList(List<T> list){
		if(list!=null && list.size()>0){
			for(int i=0;i<list.size();i++){
				T t = list.get(i);
				t.setModiDate(new Date());
				if(t.getCreateTime()==null){
					t.setCreateTime(new Date());
				}				
			}
			
		}
		baseRepo.save(list);
		RetDomain domain = new RetDomain();
		domain.setSuccessMsg("success");
		return domain;
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#save(java.lang.String, java.lang.Class)
	 */
	public T save(String body,Class<T> t){
		T entity = bodyToObj(body, t);	
		return   save(entity);
	}
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#del(java.lang.String)
	 */
	public String del(String id){
		Long _id = LongUtil.getLongValue(id, null);
		return this.del(_id);
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#del(java.lang.Long)
	 */
	public String del(Long _id){
		
		if(_id!=null){
			baseRepo.delete(_id);
			return "200";
		}else{
			return "id must not be null !";
		}
	}
	
	/**
	 * 执行单条或批量删除,id不为空，执行单条删除，id为空且ids不为空，执行批量删除
	 * @param _id
	 * @param _ids
	 * @return
	 */
	protected RetDomain delRows(Long _id,String _ids){
		
		RetDomain domain = new RetDomain();
		if(_id!=null){
			String retStr = this.del(_id);			
			
			if(retStr=="200"){
				domain.setSuccessMsg("删除操作成功");
			}else{
				domain.setErrorMsg("删除操作失败");
			}
		}else{
			if(_ids!=null){
				int nums =this.delList(_ids);
				if(nums>0){
					domain.setSuccessMsg("删除 " + nums + " 条记录成功!");
				}else{
					domain.setErrorMsg("记录不存在，删除操作失败");
				}
			}else{
				domain.setErrorMsg("删除操作失败");
			}
		}
		return domain;
	}
	
	/**
	 * 删除集合对象
	 * @param _ids
	 * @return
	 */
	public int delList(String _ids){
		
		String sql = "delete from %1$s where id in (%2$s)";
		
		
		if(_ids!=null && checkIdValue(_ids)){
			
			sql = String.format(sql, this.moduleName,_ids);
			
			return this.executeNativeDelOrUpdate(sql);
		}else{
			return -1;
		}
	}
	
	private boolean checkIdValue(String ids){
		boolean retVal = false;
		
		if(ids==null || ids.trim().length()<=0)
			return retVal;
		else{
			String[] _ids = ids.split(",");
			if(_ids.length>0){
				for(String sid:_ids){
					Long.parseLong(sid);					
				}
				retVal = true;
			}
		}
			
		return retVal;
	}
	
	/**
	 * json数据对象转换
	 * @param body json数据对象
	 * @param clazz 反序列化类实例
	 * @return 实例化的clazz对象
	 */
	protected T  bodyToObj (String body,Class<T> clazz){
		
		return  JsonUtil.bodyToObj(body, clazz);
	}
	
	/**
	 * json数据对象转换
	 * @param body json数据对象
	 * @param clazz 反序列化类实例
	 * @return 实例化的clazz对象
	 */
	@SuppressWarnings("rawtypes")
	protected Object bodyToClass (String body,Class clazz){
		
		return   JsonUtil.bodyToClass(body, clazz);
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getOne(java.lang.String)
	 */
	protected T getOne(String tid) {
		
		Long _tid = LongUtil.getLongValue(tid, null);
		return this.getOne(_tid);
	}
	
	/* (non-Javadoc)
	 * @see org.brisling.service.base.common.BaseServiceInf#getOne(java.lang.Long)
	 */
	public T getOne(Long tid) {
		
		if(tid!=null)
			return  (T) baseRepo.findOne(tid);
		
		return null;
	}
	
	protected Sort getSort(String sort){
		
		Sort _sort = defaultSort;
		if((sort!=null)&&(sort.length()>0)){
			_sort = new Sort(new String[]{sort});
		}
		return _sort;
	}	
	
	protected int executeNativeDelOrUpdate(String sql){
		
		return entityManager.createNativeQuery(sql).executeUpdate();
	}	
	
	/**
	 * 更新审核标志位
	 * @param id
	 * @param status
	 * @return
	 */
	protected String updateAuditStatus(Long id,String status){
		String sql = String.format("update %1$s set status = %2$s where id= %3$d",this.moduleName,status,id);
		
		entityManager.createNativeQuery(sql).executeUpdate();
		
		return "200";
	}
	
	/**
	 * 更新审核标志位
	 * @param ids
	 * @param status
	 * @return
	 */
	protected int updateAuditStatusList(String ids,String status){		
		
		if(ids!=null && this.checkIdValue(ids)){
			String sql = String.format("update %1$s set status = %2$s where id in (%3$s)",this.moduleName,status,ids);
			
			return entityManager.createNativeQuery(sql).executeUpdate();
		}else{
			return -1;
		}
		
	}
	
	
	public CriteriaBuilder getCriteriaBuilder(){
		if(this.criteriaBuilder ==null)
			this.criteriaBuilder = entityManager.getCriteriaBuilder();
		return this.criteriaBuilder;
	}
	
	public CriteriaQuery<T> getCriteriaQuery(){
		if(this.criteriaQuery == null)
			this.criteriaQuery=this.getCriteriaBuilder().createQuery(clazz);
		return this.criteriaQuery;
	}
	
	public Root<T> getRoot(){
		if(this.root==null)
			this.root = this.getCriteriaQuery().from(clazz);
		
		return this.root;
	}
	
	/**
	 * 分页动态条件查询及排序
	 * @param t	实体类对象
	 * @param condition	动态条件
	 * @param sort	动态排序
	 * @param page	页号
	 * @param rows	行数
	 * @return	java.util.List 实体结果集
	 */
	public List<T> getCriteriaList(HashMap<String,Object> condition,HashMap<String,String> sort,int page,int rows){
		
		CriteriaBuilder _criteriaBuilder = this.getCriteriaBuilder();
		CriteriaQuery<T> _criteriaQuery = this.getCriteriaQuery();
		Root<T> _root = this.getRoot();
		_criteriaQuery.select(_root);
		
		for(String field:condition.keySet()){
			
			Class<?> clz = getFieldClass(field,clazz);
			if(clz!=null){
				_criteriaQuery.where(
					 _criteriaBuilder.and(
							 _criteriaBuilder.equal(_root.get(field).as(clz), condition.get(field)) 
					 
					));
			}
		}
		
		_criteriaQuery.orderBy(this.getCriteriaOrder(sort));
		
		return this.getPagedCriteriaList(_criteriaQuery, page, rows);
		
	}
	
	/**
	 * 分页动态条件查询及排序
	 * @param t	实体类对象
	 * @param condition	动态条件
	 * @param sort	动态排序
	 * @param page	页号
	 * @param rows	行数
	 * @return	java.util.List 实体结果集
	 */
	public List<T> getCriteriaList(List<Predicate> condition,HashMap<String,String> sort,int page,int rows){
		
		CriteriaQuery<T> _criteriaQuery = this.getCriteriaQuery();
		_criteriaQuery.select(this.getRoot());
		Predicate[] predicateArr = new Predicate[condition.size()];
		condition.toArray(predicateArr);
		_criteriaQuery.where(predicateArr);
		_criteriaQuery.orderBy(this.getCriteriaOrder(sort));
		
		return this.getPagedCriteriaList(_criteriaQuery, page, rows);
	}
	
	/**
	 * 分页动态条件查询及排序
	 * @param _criteriaQuery	criteria查询
	 * @param page				页号
	 * @param rows				每页行数
	 * @return	分页查询的结果集
	 */
	public List<T> getPagedCriteriaList(CriteriaQuery<T> _criteriaQuery,int page,int rows){
		page=page<=0?ConstSysParam.PAGE:page;
		rows =rows<=0?ConstSysParam.ROWS:rows;
		
		Integer[] pageParam = this.getPageParam(page, rows);
		
		return entityManager.createQuery(_criteriaQuery)
				.setFirstResult(pageParam[0])
				.setMaxResults(pageParam[1])
				.getResultList();
	}
	
	
	
	
	/**
	 * 获取动态查询排序条件
	 * @param sort
	 * @return
	 */
	private List<Order> getCriteriaOrder(HashMap<String,String> sort){
		CriteriaBuilder _criteriaBuilder = this.getCriteriaBuilder();
		List<Order> orders = new ArrayList<Order>();
		if((sort!=null)&&(sort.size()>0)){
			
			
			for(String sortKey:sort.keySet()){				
				if(sortKey!=null){
					Class<?> clz = getFieldClass(sortKey,clazz);
					if(clz!=null){
						String order = sort.get(sortKey);
						if((order!=null)&&(order.trim().toLowerCase().compareTo("desc")==0)){
							orders.add(_criteriaBuilder.desc(root.get(sortKey).as(clz)));
						}else{
							orders.add(_criteriaBuilder.asc(root.get(sortKey).as(clz)));
						}
					}
				}
			}
			
			
		}
		
		return orders;
	}
	
}
